package gggameserver.games;

import gggameserver.exceptions.GGCancel;
import gggameserver.exceptions.GGIllegalMoveFormat;
import gggameserver.exceptions.GGTimeout;
import gggameserver.games.khet.KhetBoard;
import gggameserver.games.khet.KhetCommandFormatter;

public class GameJudge implements Runnable {

    public int limiit = -1;
    
	enum State {
		INITIALIZED, RUNNING, ENDED, CANCELLED
	};

	State state = State.INITIALIZED;

	Board board;
	GameLog gameLog;
	GGGameListener listener;

	boolean cancelGame = false;

	// public GameJudge(Player player1, Player player2, Game game, Properties
	// props) {
	// this.player1 = player1;
	// this.player2 = player2;
	// this.game = game;
	//
	// this.properties = (null != props ? props : new Properties());
	// this.gameLog = new GameLog();
	//
	// if (null == this.player1)
	// throw new NullPointerException("Player 1 is not set");
	// if (null == this.player2)
	// throw new NullPointerException("Player 2 is not set");
	// if (null == this.game)
	// throw new NullPointerException("Game is not set");
	// }

	public GameJudge(Board board) {
		init(board, null);
	}

	public GameJudge(Board board, GGGameListener listener) {
		init(board, listener);
	}

	private void init(Board board, GGGameListener listener) {
		this.board = board;
		this.gameLog = new GameLog();
		this.listener = listener;
	}

	public boolean wasCancelled() {
		return isCancelled();
	}

	public synchronized void setState(State new_state) {
		state = new_state;
	}

	public synchronized void cancelGame() {
		if (state == State.ENDED || state == State.CANCELLED)
			return;

		cancelGame = true;
		state = State.CANCELLED;
	}

	private synchronized boolean isCancelled() {
		return cancelGame;
	}

	public void playGame() {
		if (isCancelled())
			return;
		setState(State.RUNNING);

		for (Player p : this.board.getPlayers()) {
		    gameLog.addPlayer(p.getPlayerNumber(), p.getName());
			if (!p.isHandshakeSent())
				p.sendHandshake();
		}

		int move_nr = 0;
		// GGTimeLimit timelimit = new GGTimeLimit(this.board);
		while (!board.isGameOver()) {
			if (isCancelled())
				return;

			move_nr++;
			Player player = this.board.getActivePlayer();

			// if first move, then send game start
			if (move_nr == 1)
				for (Player p : this.board.getPlayers())
					p.sendStart(player == p);

			Move move = null;
			int time = 0;
			try {
				if (null != listener)
					listener.gameMove(player.getPlayerNumber());

				// int limit = timelimit.getMoveTimeLimit(player);
				int limit = this.limiit;
//				int limit = 10000;
				long start_ms = System.currentTimeMillis();
KhetBoard kb = (KhetBoard)board;
				gameLog.addBoard(KhetCommandFormatter.getGameCommandAsString(kb)); // TODO 
				move = getMove(player, limit);
				long end_ms = System.currentTimeMillis();

				time = (int) (end_ms - start_ms);
				if (time < 0)
					time = 0; // TODO time control
					// timelimit.setLastMoveTime(player, time);
			} catch (GGTimeout e) {
				// TODO Auto-generated catch block
				// e.printStackTrace();
				gameLog.addError(player.getPlayerNumber(), "Timeout", "");
				board.timeout();
			} catch (GGIllegalMoveFormat e) {
				// TODO Auto-generated catch block
				// e.printStackTrace();
				gameLog.addError(player.getPlayerNumber(),
						"Illegal move format", e.getMoveText());
				board.illegalMove();
			} catch (GGCancel e) {
				//
				return;
			}

			if (null == move) {
				; // TODO
			} else if (board.isLeagal(move)) {
				gameLog.addMove(player.getPlayerNumber(),
						board.moveToCommand(move), time);
				if (null != listener)
					listener.beforeMove(move);
				synchronized (board) {
					board.makeMove(move);
				}
				if (null != listener)
					listener.boardUpdate();
				Player next_player = this.board.getActivePlayer();
				for (Player p : this.board.getPlayers())
					if (p != player)
						p.sendMove(move, next_player == p);
			} else {
				gameLog.addError(player.getPlayerNumber(), "Illegal move",
						board.moveToCommand(move));
				board.illegalMove();
				; // TODO
			}
		}

KhetBoard kb = (KhetBoard)board;
        gameLog.addBoard(KhetCommandFormatter.getGameCommandAsString(kb)); // TODO 

        if (null != listener)
			listener.gameEnd(getWinner());
		for (Player p : this.board.getPlayers())
			p.sendResult(this.board.getPlayerResult(p.getPlayerNumber()));
		// p.sendResult(this.board.getPlayerResult(p.getPlayerNumber()));

		setState(State.ENDED);
	}

	public int getWinner() {
		return this.board.getWinner();
	}

	public String getGameLogText() {
		return this.gameLog.getLogText();
	}

	public String getGameLogData() {
		return this.gameLog.getLogText();
	}

	private Move getMove(Player player, int limit) throws GGTimeout,
			GGIllegalMoveFormat, GGCancel {
		return player.getMove(limit);
	}

	public void run() {
		// TODO Auto-generated method stub

	}

	public Board getBoard() {
		return board;
	}

	// public void playGame() {
	// Board board = this.game.getInitialBoard();
	// int move_nr = 0;
	// while (!board.isGameOver()) {
	// move_nr++;
	// Player player = this.board.ge;
	// Player opponent;
	// if (1 == player_nr) {
	// player = this.player1;
	// opponent = this.player2;
	// } else if (2 == player_nr) {
	// player = this.player2;
	// opponent = this.player1;
	// } else {
	// throw new IllegalStateException("Illegal player nr" + player_nr);
	// }
	//
	// if (move_nr == 1) {
	// player.sendStart(true);
	// opponent.sendStart(false);
	// }
	//
	// Move move = player.getMove();
	// if (board.makeMove(move))
	// opponent.sendMove(move);
	// }
	// sendResult(player1, 1, board);
	// sendResult(player2, 2, board);
	// }

}
